#pragma once

#include <stdexcept>
#include <unordered_map>
#include <unordered_set>

#include "common/enum_defs.h"
#include "common/macros.h"
#include "common/node_utils.h"
#include "nodes/nodes.h"
#include "planner/expression.h"

namespace optimizer {

/**
 * typedef for GroupID
 */

using group_id_t = int32_t;
using plan_node_id_t = int32_t;

/**
 * Definition for a UNDEFINED_GROUP
 */
const group_id_t UNDEFINED_GROUP = group_id_t(-1);

/**
 * Enumeration defining external file formats
 */
enum class ExternalFileFormat { CSV };

/**
 * OrderBy ordering
 */
enum class OrderByOrderingType { ASC, DESC };

#define OPERATOR_TYPE_ENUM(T)               \
  T(OperatorType, UNDEFINED)                \
                                            \
  T(OperatorType, LeafOperator)             \
                                            \
  T(OperatorType, LogicalGet)               \
  T(OperatorType, LogicalLimit)             \
  T(OperatorType, LogicalJoin)              \
  T(OperatorType, LogicalAggregate)         \
                                            \
  T(OperatorType, LogicalUnion)             \
  T(OperatorType, LogicalIntersect)         \
  T(OperatorType, Logicalexcept)            \
                                            \
  T(OperatorType, LOGICALPHYSICALDELIMITER) \
                                            \
  T(OperatorType, PhysicalSeqScan)          \
  T(OperatorType, OrderBy)                  \
  T(OperatorType, Limit)

ENUM_DEFINE(OperatorType, uint8_t, OPERATOR_TYPE_ENUM);
#undef OPERATOR_TYPE_ENUM

struct ExprEqualCmp {
  bool operator()(Expression *lhs, Expression *rhs) {
    CASCADES_ASSERT(lhs != nullptr && rhs != nullptr, "Expression should not be null");
    return equal(lhs, rhs);
  }

  bool operator()(const Expression *lhs, const Expression *rhs) const {
    CASCADES_ASSERT(lhs != nullptr && rhs != nullptr, "Expression should not be null");
    return equal(lhs, rhs);
  }
};

struct ExprHasher {
  size_t operator()(const Expression *expr) const {
    CASCADES_ASSERT(expr != nullptr, "Expression should not be null");
    return NodeUtils::ExprHash(expr);
  }
};

using ExprMap = std::unordered_map<Expression *, unsigned, ExprHasher, ExprEqualCmp>;

using ExprSet = std::unordered_set<Expression *, ExprHasher, ExprEqualCmp>;

}  // namespace optimizer
